#ifndef __GLESHardwarePixelBuffer_H__
#define __GLESHardwarePixelBuffer_H__


#include "U2GLESPreRequest.h"
#include "U2HardwarePixelBuffer.h"


U2EG_NAMESPACE_BEGIN


class U2RenderTexture;


class _U2GLESShare GLESHardwarePixelBuffer: public U2HardwarePixelBuffer
{
protected:
    /// Lock a box
    U2PixelBox lockImpl(const U2Image::Box lockBox,  LockOptions options);

    /// Unlock a box
    void unlockImpl(void);

    // Internal buffer; either on-card or in system memory, freed/allocated on demand
    // depending on buffer usage
    U2PixelBox mBuffer;
    GLenum mGLInternalFormat; // GL internal format
    LockOptions mCurrentLockOptions;

    // Buffer allocation/freeage
    void allocateBuffer();

    void freeBuffer();

    // Upload a box of pixels to this buffer on the card
    virtual void upload(const U2PixelBox &data, const U2Image::Box &dest);

    // Download a box of pixels from the card
    virtual void download(const U2PixelBox &data);

public:
    /// Should be called by HardwareBufferManager
    GLESHardwarePixelBuffer(size_t mWidth, size_t mHeight, size_t mDepth,
                          PixelFormat mFormat,
                          U2HardwareBuffer::Usage usage);

    /// @copydoc U2HardwarePixelBuffer::blitFromMemory
    void blitFromMemory(const U2PixelBox &src, const U2Image::Box &dstBox);

    /// @copydoc U2HardwarePixelBuffer::blitToMemory
    void blitToMemory(const U2Image::Box &srcBox, const U2PixelBox &dst);

    virtual ~GLESHardwarePixelBuffer();

    /** Bind surface to frame buffer. Needs FBO extension.
    */
    virtual void bindToFramebuffer(GLenum attachment, size_t zoffset);
    GLenum getGLFormat() { return mGLInternalFormat; }
};


/** Texture surface.
*/
class _U2GLESShare GLESTextureBuffer: public GLESHardwarePixelBuffer
{
public:
    /** Texture constructor */
    GLESTextureBuffer(const U2String &baseName, GLenum target, GLuint id, GLint width, GLint height, GLint internalFormat, 
                    GLenum format, GLint face, GLint level, Usage usage, bool softwareMipmap, bool writeGamma, u2uint fsaa);
    virtual ~GLESTextureBuffer();

    /// @copydoc U2HardwarePixelBuffer::bindToFramebuffer
    virtual void bindToFramebuffer(GLenum attachment, size_t zoffset);

    /// @copydoc U2HardwarePixelBuffer::getRenderTarget
    /**********************@@@@@@@@@@@@@@@@@@@@@
    RenderTexture* getRenderTarget(size_t);
    */

    /// Upload a box of pixels to this buffer on the card
    virtual void upload(const U2PixelBox &data, const U2Image::Box &dest);

    /// Download a box of pixels from the card
    virtual void download(const U2PixelBox &data);

    /// Hardware implementation of blitFromMemory
    virtual void blitFromMemory(const U2PixelBox &src_orig, const U2Image::Box &dstBox);

    /// Notify TextureBuffer of destruction of render target
    void _clearSliceRTT(size_t zoffset)
    {
        mSliceTRT[zoffset] = 0;
    }

    // Copy from framebuffer
    void copyFromFramebuffer(size_t zoffset);

    /// @copydoc U2HardwarePixelBuffer::blit
    void blit(const U2HardwarePixelBufferSharedPtr &src, const U2Image::Box &srcBox, const U2Image::Box &dstBox);
    // Blitting implementation
    void blitFromTexture(GLESTextureBuffer *src, const U2Image::Box &srcBox, const U2Image::Box &dstBox);

protected:
    // In case this is a texture level
    GLenum mTarget;
    GLenum mFaceTarget; // same as mTarget in case of GL_TEXTURE_xD, but cubemap face for cubemaps
    GLuint mTextureID;
    GLint mFace;
    GLint mLevel;
    bool mSoftwareMipmap;

    typedef std::vector<U2RenderTexture*> SliceTRT;
    SliceTRT mSliceTRT;

    static void buildMipmaps(const U2PixelBox &data);
};


 /** Renderbuffer surface.  Needs FBO extension.
 */
class _U2GLESShare GLESRenderBuffer: public GLESHardwarePixelBuffer
{
public:
    GLESRenderBuffer(GLenum format, size_t width, size_t height, GLsizei numSamples);
    virtual ~GLESRenderBuffer();

    /// @copydoc GLHardwarePixelBuffer::bindToFramebuffer
    virtual void bindToFramebuffer(GLenum attachment, size_t zoffset);

protected:
    // In case this is a render buffer
    GLuint mRenderbufferID;
};


U2EG_NAMESPACE_END


#endif
